home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-11-02 | 36.8 KB | 1,605 lines |
- Newsgroups: comp.sources.misc
- subject: v08i104: Make Version 1.5 (Part 1 of 3)
- From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
- Reply-To: greggy@etude.UUCP (Greg Yachuk)
-
- Posting-number: Volume 8, Issue 104
- Submitted-by: greggy@etude.UUCP (Greg Yachuk)
- Archive-name: make.gy/part01
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 1 (of 3)."
- # Contents: MANIFEST README build.c make.c tstring.c
- # Wrapped by greggy@etude on Mon Oct 30 19:10:07 1989
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'MANIFEST' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'MANIFEST'\"
- else
- echo shar: Extracting \"'MANIFEST'\" \(548 characters\)
- sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
- X File Name Archive # Description
- X-----------------------------------------------------------
- X MANIFEST 1 This shipping list
- X README 1
- X build.c 1
- X decl.h 3
- X default.dos 3
- X default.mk 3
- X make.c 1
- X make.doc 2
- X make.h 3
- X makefile 3
- X makefile.dos 3
- X parse.c 2
- X tstring.c 1
- X tstring.h 3
- END_OF_FILE
- if test 548 -ne `wc -c <'MANIFEST'`; then
- echo shar: \"'MANIFEST'\" unpacked with wrong size!
- fi
- # end of 'MANIFEST'
- fi
- if test -f 'README' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'README'\"
- else
- echo shar: Extracting \"'README'\" \(4707 characters\)
- sed "s/^X//" >'README' <<'END_OF_FILE'
- XMake Version 1.5 89-10-30
- X
- XThis is a work-alike program, very close to `make' as it exists on Sun
- Xsystems. It is compiled with Microsoft C (5.1) and runs on PCDOS 3.3.
- XIt also compiles and runs on BSD 4.2 Unix.
- X
- XMany thanks to Kirk Bailey (bailey@mist.cs.orst)
- X Brian Wilson (island!sun!grenada!dr_unix)
- X Jeff Fried (ames!culls!jeff)
- X Arend van den Brug (arend@philmds@philnl@mcvax)
- Xfor pointing out problems and improvements.
- X
- XI have included a makefile and a (rudimentary) default.mk for BSD Unix.
- XUpdates, additions and corrections are welcomed. The shar distribution
- Xhas the filenames reversed from the ZOO distribution:
- X
- X ZOO distribution shar distribution
- X ---------------------------- --------------------------
- X makefile makefile.bsd makefile.dos makefile
- X default.mk default.bsd default.dos default.mk
- X
- X
- XThis is because I assume that the ZOO is used on DOS and the shar on
- XUnix. If what you got is not appropriate, rename the appropriate files
- Xand make. For example, if you got the DOS version on a Unix system:
- X
- X mv makefile makefile.dos
- X mv makefile.bsd makefile
- X mv default.mk default.dos
- X mv default.bsd default.mk
- X make
- X
- XAlternatively, you can (probably) just use this following command:
- X
- X make -r -f default.bsd -f makefile.bsd
- X
- XThis is version 1.5. There is a version 1.4 that was submitted to
- Xcomp.binaries.ibm.pc by Arend van den Brug. I have incorporated many of
- Xthe changes into my version and called it 1.5. These are the changes
- Xfrom 1.3 to 1.5:
- X support the -k, -S and -q options (see make.man).
- X
- X correctly support the $(MAKE) macro.
- X
- X allow target lines to end with a semi-colon and a command.
- X
- X corrected bugs when allocated strings are over-run.
- X
- X added "*" and "?" to the list of characters that force the use
- X of the shell on Unix
- X
- X
- XThese are the changes from 1.2 to 1.3:
- X don't append shell command lines when encountering multiple
- X targets of the same name. if this is a *special* target
- X (e.g. .c.obj), just override. otherwise exit with an error.
- X
- X flush output before executing the command, so the output comes
- X out in the right order when redirecting stdout to a file.
- X
- X if a file is supposedly built, but does not exists, use current time.
- X
- X exit with an error if a target line does not have a ':'.
- X
- X don't force a space after "include" in case TAB is used.
- X
- X D and F modifiers for Directory and Filename of $@, $<, $*.
- X
- X use a dependent file for an implicit rule, if possible.
- X
- X allow Makefile as well as makefile, for Unix.
- X
- X always print statements when using -n, even if they start with @.
- X
- X backquote (`) will force use of a shell, in Unix.
- X
- XThese are the changes from 1.1 to 1.2:
- X ensure command line macros override makefile macros, even as
- X makefiles are being read in.
- X
- X support time checks correctly on MSDOS directories.
- X
- X use MAKEFLAGS macro, and set it up for subordinate makes.
- X
- X import environment variables and support -e flag.
- X
- X handle `-f -' (i.e. makefile from stdin) correctly.
- X
- X clean up some potential NULL pointer dereferences.
- X
- X correct errors in handling nested makes.
- X
- X modify tokenizing routine to correctly handle trailing separators.
- X
- X the documentation has been re-written
- X
- XThese are the changes from 1.0 to 1.1:
- X modify prerequisite list handling to correctly allow a target to
- X appear on multiple target lines.
- X
- XThere is a short story which goes with this offering. Sometime early in
- X1988, someone (possibly Dan Grayson) posted copyrighted source for a
- X`make' to Usenet. I used it and modified it somewhat, and then lost my
- Xhard disk. Having found this program to be very useful, I set about
- Xrewriting it from my recollection of the source that I had seen. I have
- Xasked Rahul (moderator of comp.binaries.ibm.pc) if he could trace the
- Xoriginal submitter, and have also posted a note to the net in c.b.i.p.d,
- Xtrying to locate this person. So far, no trace has been found. I
- Xreally would like to show this source to him(and hopefully have him
- Xagree that it is not the same as his).
- X
- XI have based my algorithms on this previous source code. These are not
- Xcopyrightable, so I feel that I have not infringed upon anyone's rights.
- XAlso, I feel that I have acted in good faith trying to trace this
- Xperson. I hope that recipients of this code feel the same. I am
- Xreleasing this into the public domain. You may do anything you wish
- Xwith it, even copyright it yourself and try to sell it as your own.
- XGood luck, and have fun.
- X
- X -greg
- X
- XGreg Yachuk Informix Software Inc., Menlo Park, CA (415) 926-6300
- X{uunet,pyramid}!infmx!greggy why yes, I DID choose that login myself
- END_OF_FILE
- if test 4707 -ne `wc -c <'README'`; then
- echo shar: \"'README'\" unpacked with wrong size!
- fi
- # end of 'README'
- fi
- if test -f 'build.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'build.c'\"
- else
- echo shar: Extracting \"'build.c'\" \(4850 characters\)
- sed "s/^X//" >'build.c' <<'END_OF_FILE'
- X/*
- X * build.c An imitation of the Unix MAKE facility
- X *
- X * 88-10-01 v1.0 created by greg yachuk, placed in the public domain
- X * 88-10-06 v1.1 changed prerequisite list handling
- X * 88-11-11 v1.2 fixed some bugs and added environment variables
- X * 89-07-12 v1.3 stop appending shell commands, and flush output
- X * 89-08-01 v1.4 AB lots of new options and code
- X * 89-10-30 v1.5 greggy -f -S -q options, took some changes from v1.4
- X *
- X */
- X
- X#include <stdio.h>
- X#include <string.h>
- X#ifdef MSDOS
- X#include <stdlib.h>
- X#include <process.h>
- X#else
- X#include <sys/wait.h>
- X#endif
- X
- X#include "make.h"
- X#include "tstring.h"
- X#include "decl.h"
- X
- Xchar *shell_cmds[] = {
- X#ifdef MSDOS
- X "dir", "type", "rem", "pause", "date", "time", "ren", "rename",
- X "ver", "vol", "break", "verify", "mkdir", "md", "exit", "ctty",
- X "echo", "if", "cls", "chdir", "cd", "rmdir", "rd", "copy", "del",
- X "erase",
- X#endif
- X NULL,
- X};
- X
- X/*
- X * build - process the shell commands
- X */
- Xbuild(shellp)
- XREGISTER shellptr *shellp;
- X{
- X REGISTER char **argv; /* argified version of scmd */
- X int runst; /* exec return status */
- X char *scmd; /* command with symbols broken out */
- X char *tcmd; /* copy of scmd for `tokenize' */
- X char *errnum; /* error number in ascii */
- X char *errmsg; /* error message */
- X#ifdef MSDOS
- X char **shcp; /* pointer to shell command list */
- X#endif
- X
- X if (shellp == NULL || opts.query)
- X return (0);
- X
- X for (; *shellp != NULL;
- X tfree(scmd), tfree(tcmd), tfree(argv), ++shellp)
- X {
- X /* breakout runtime symbols (e.g. $* $@ $<) */
- X scmd = breakout((*shellp)->scmd);
- X
- X if (!opts.silent && (opts.noexec || !(*shellp)->s_silent))
- X {
- X puts(scmd);
- X fflush(stdout);
- X }
- X
- X /* make a copy because tokenize litters '\0's */
- X tcmd = tstrcpy(scmd);
- X argv = tokenize(tcmd);
- X
- X /* look for $(MAKE) */
- X if (equal(argv[0], opts.make))
- X {
- X /* call ourselves recursively */
- X new_make(argv);
- X continue;
- X }
- X
- X if (opts.noexec)
- X continue;
- X
- X /* any SHELL meta-characters MUST be handled by the shell */
- X if (!(*shellp)->s_shell && strpbrk(scmd, SHELL_METAS))
- X (*shellp)->s_shell = 1;
- X#ifdef MSDOS
- X /* likewise, check for COMMAND.COM builtin commands */
- X shcp = shell_cmds;
- X for (; !(*shellp)->s_shell && *shcp; ++shcp)
- X (*shellp)->s_shell = equal(*shcp, argv[0]);
- X#endif
- X /* run without COMMAND.COM if possible, 'cause it uses RAM */
- X if ((*shellp)->s_shell)
- X runst = system(scmd);
- X else
- X runst = spawnvp(P_WAIT, argv[0], argv);
- X
- X if (runst == 0)
- X continue;
- X
- X /* uh-oh, an error */
- X if (runst == -1)
- X perror("make");
- X
- X errnum = talloc(18);
- X#ifdef MSDOS
- X errnum = itoa(runst, errnum, 10);
- X#else
- X sprintf(errnum, "%d", runst);
- X#endif
- X errmsg = (opts.keepon) ? "\007*** Ignoring Error code "
- X : "\007*** Error code ";
- X errmsg = tstrcat(errmsg, errnum);
- X terror(0, errmsg);
- X tfree(errmsg);
- X tfree(errnum);
- X
- X if (opts.keepon)
- X return (1);
- X
- X if (!opts.ignore && !(*shellp)->s_ignore)
- X exit(1);
- X }
- X
- X return (0);
- X}
- X
- X
- X/*
- X * new_make - save current environment
- X * - call make() recursively (actually main())
- X * - clean up new environment
- X * - restore environment
- X */
- Xnew_make(argv)
- Xchar **argv;
- X{
- X targptr thead, tnext, tsuffix;
- X fileptr fhead, fnext;
- X symptr shead, snext;
- X shellptr shhead, shnext;
- X char **ttlist;
- X long tnow;
- X optnode topts;
- X int i;
- X
- X /* save all the globals */
- X tsuffix = suffix_targ;
- X thead = target_list;
- X fhead = file_list;
- X shead = symbol_list;
- X shhead = shell_list;
- X ttlist = tlist;
- X tnow = now;
- X topts = opts;
- X
- X /* count the arguments */
- X for (i = 0; argv[i]; ++i)
- X tunquote(argv[i]);
- X
- X /* call ourselves recursively; this inherits flags */
- X ++make_level;
- X main(i, argv);
- X --make_level;
- X
- X /* we're back, so gotta clean up and dispose of a few things */
- X while (target_list)
- X {
- X tnext = target_list->tnext;
- X if (target_list->tpreq)
- X tfree(target_list->tpreq);
- X if (target_list->tshell)
- X tfree(target_list->tshell);
- X tfree(target_list);
- X target_list = tnext;
- X }
- X
- X while (file_list)
- X {
- X fnext = file_list->fnext;
- X tfree(file_list->fname);
- X tfree(file_list);
- X file_list = fnext;
- X }
- X
- X /* don't drop all symbols, just the new ones */
- X
- X while (symbol_list != shead)
- X {
- X snext = symbol_list->snext;
- X tfree(symbol_list->sname);
- X tfree(symbol_list->svalue);
- X tfree(symbol_list);
- X symbol_list = snext;
- X }
- X
- X while (shell_list)
- X {
- X shnext = shell_list->slink;
- X tfree(shell_list->scmd);
- X tfree(shell_list);
- X shell_list = shnext;
- X }
- X
- X /* restore our original globals */
- X suffix_targ = tsuffix;
- X target_list = thead;
- X file_list = fhead;
- X symbol_list = shead;
- X shell_list = shhead;
- X tlist = ttlist;
- X now = tnow;
- X opts = topts;
- X}
- X
- X
- X#ifndef MSDOS
- Xint
- Xspawnvp(mode, path, args)
- Xint mode;
- Xchar *path;
- Xchar **args;
- X{
- X int pid = 0;
- X union wait waitword;
- X
- X if (mode != P_OVERLAY)
- X pid = fork();
- X
- X if (pid == 0)
- X execvp(path, args);
- X
- X wait(&waitword);
- X return (waitword.w_retcode);
- X}
- X#endif
- END_OF_FILE
- if test 4850 -ne `wc -c <'build.c'`; then
- echo shar: \"'build.c'\" unpacked with wrong size!
- fi
- # end of 'build.c'
- fi
- if test -f 'make.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'make.c'\"
- else
- echo shar: Extracting \"'make.c'\" \(17680 characters\)
- sed "s/^X//" >'make.c' <<'END_OF_FILE'
- X/*
- X * make.c An imitation of the Unix MAKE facility
- X *
- X * 88-10-01 v1.0 created by greg yachuk, placed in the public domain
- X * 88-10-06 v1.1 changed prerequisite list handling
- X * 88-11-11 v1.2 fixed some bugs and added environment variables
- X * 89-07-12 v1.3 stop appending shell commands, and flush output
- X * 89-08-01 v1.4 AB lots of new options and code
- X * 89-10-30 v1.5 greggy -f -S -q options, took some changes from v1.4
- X *
- X */
- X
- X#include <stdio.h>
- X#include <errno.h>
- X#include <fcntl.h>
- X#include <string.h>
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X#ifdef MSDOS
- X#include <stdlib.h>
- X#endif
- X
- X#include "make.h"
- X#include "tstring.h"
- X#include "decl.h"
- X
- X
- Xtargptr target_list = NULL; /* list of target nodes */
- Xfileptr file_list = NULL; /* list of file nodes */
- Xsymptr symbol_list = NULL; /* list of symbol nodes */
- Xshellptr shell_list = NULL; /* list of shell nodes */
- X
- Xint make_level = 0; /* for counting new_make()'s */
- X
- Xtargptr first_targ = NULL; /* first target, in case nothing explicit */
- Xtargptr suffix_targ = NULL; /* .SUFFIXES target pointer */
- X
- Xchar **tlist = NULL; /* command line targets */
- Xchar **flist = NULL; /* command line make files */
- Xchar **mlist = NULL; /* command line macros */
- X
- Xint tmax = 0; /* max size of tlist */
- Xint fmax = 0; /* max size of flist */
- Xint mmax = 0; /* max size of mlist */
- X
- Xoptnode opts; /* all the options */
- Xint readdef = 1; /* -r option */
- Xint dispcount = 0; /* used for -D option */
- X
- Xlong now; /* time at startup */
- Xchar *makeflags; /* value to update the MAKEFLAGS macro with */
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X REGISTER int i;
- X REGISTER targptr targp;
- X REGISTER int mk;
- X symptr symp;
- X char *envp;
- X char **envv;
- X
- X /* initialize the various global lists */
- X
- X opts.depend = 0;
- X dispcount = 0;
- X
- X target_list = NULL;
- X file_list = NULL;
- X shell_list = NULL;
- X /* don't set symbol_list to NULL, or recursive makes won't work */
- X
- X /* allocate space for command line targets, files and macros */
- X
- X tlist = grow_list(NULL, &tmax);
- X flist = grow_list(NULL, &fmax);
- X mlist = grow_list(NULL, &mmax);
- X
- X /* process MAKEFLAGS environment variable, first */
- X
- X symp = get_symbol("MAKEFLAGS", 0);
- X if (symp->svalue != NULL)
- X {
- X /* chop up the MAKEFLAGS and feed them to to make_args() */
- X
- X envp = tstrcpy(symp->svalue);
- X envv = tokenize(envp);
- X for (i = 0; envv[i] != NULL; i++);
- X make_args(i, envv);
- X
- X /* free the vector of pointers, and the string itself, */
- X /* since you cannot have macros, targets or makefiles */
- X /* in the MAKEFLAGS macro. */
- X
- X tfree(envv);
- X tfree(envp);
- X tfree(makeflags); /* ignore this, since we just read it */
- X }
- X
- X make_args(--argc, ++argv); /* process command line options */
- X
- X add_macro(makeflags, 0);/* update the MAKEFLAGS macro */
- X tfree(makeflags);
- X
- X /* add command line macros, so they DON'T get overridden */
- X
- X for (i = 0; mlist[i] != NULL; i++)
- X add_macro(mlist[i], 1);
- X
- X tfree(mlist); /* all done with macros */
- X
- X if (opts.query) /* -q never executes anything */
- X opts.noexec = 1;
- X
- X if (opts.noexec)
- X opts.touch = 0; /* -n never touches */
- X
- X if (dispcount > 1) /* display `default.mk' on -DD */
- X opts.display = 1;
- X
- X first_targ = NULL; /* used in parse() */
- X
- X if (readdef) /* read in `default.mk' */
- X parse(fopenp(MAKEINI, "r"));
- X
- X if (dispcount > 0) /* display makefile's on -D */
- X opts.display = 1;
- X
- X first_targ = NULL; /* get first target in `makefile' */
- X
- X /* parse the makefiles given on command line */
- X for (i = 0; flist[i] != NULL; i++)
- X {
- X parse(equal(flist[i], "-") ? fdopen(dup(fileno(stdin)), "r")
- X : fopen(flist[i], "r"));
- X }
- X
- X /* no makefiles specified, so use "makefile" or "Makefile" */
- X if (i == 0)
- X {
- X if (parse(fopen("makefile", "r")) == 0)
- X {
- X#ifndef MSDOS
- X parse(fopen("Makefile", "r"));
- X#endif
- X }
- X }
- X
- X tfree(flist); /* all done with makefile's */
- X
- X /* find the current value of the $(MAKE) macro */
- X symp = get_symbol("MAKE", 0);
- X opts.make = (symp->svalue == NULL) ? "make" : symp->svalue;
- X
- X if ((targp = get_target(".INIT")) != NULL)
- X build(targp->tshell); /* process the .INIT rule */
- X
- X mk = 0;
- X
- X for (i = 0; tlist[i] != NULL; i++)
- X {
- X /* process command line arguments */
- X mk |= (make(tlist[i], 1) > 0) ? 1 : 0;
- X }
- X
- X tfree(tlist); /* all done with targets */
- X
- X /* if no targets specified, make the first one */
- X if (i == 0 && first_targ)
- X mk |= (make(first_targ->tfile->fname, 1) > 0) ? 1 : 0;
- X
- X if ((targp = get_target(".DONE")) != NULL)
- X build(targp->tshell); /* process the .DONE rule */
- X
- X return (mk & opts.query); /* not exit(); see new_make() */
- X}
- X
- X
- X/*
- X * make_args - process the command line arguments
- X */
- Xmake_args(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X REGISTER int tlen;
- X REGISTER int flen;
- X REGISTER int mlen;
- X REGISTER int no_k = 0; /* override the -k option */
- X char *tmf;
- X int addflag;
- X
- X now = time(NULL); /* get current date & time */
- X
- X makeflags = tstrcpy("MAKEFLAGS+=");
- X
- X tlen = flen = mlen = 0;
- X
- X for (; argc != 0; ++argv, --argc)
- X {
- X if (**argv != '-')
- X {
- X /* doesn't start with '-'; must be macro or target */
- X
- X if (strchr(*argv, '='))
- X { /* store as a macro */
- X if (mlen == mmax)
- X mlist = grow_list(mlist, &mmax);
- X mlist[mlen++] = *argv;
- X }
- X else
- X { /* store as a target */
- X if (tlen == tmax)
- X tlist = grow_list(tlist, &tmax);
- X tlist[tlen++] = *argv;
- X }
- X continue;
- X }
- X
- X /* must be an option */
- X
- X tmf = tstrcat(makeflags, *argv);
- X
- X while (*argv && *++*argv)
- X {
- X addflag = 1; /* add to MAKEFLAGS */
- X switch (**argv)
- X {
- X case 'd': /* show dependencies */
- X addflag = 0; /* don't add to MAKEFLAGS */
- X opts.depend++;
- X break;
- X
- X case 'D': /* display makefiles */
- X dispcount++;
- X break;
- X
- X case 'e': /* don't override environment */
- X opts.envirn = 1;
- X break;
- X
- X case 'f': /* new makefile name */
- X addflag = 0; /* don't add to MAKEFLAGS */
- X if (argc < 2)
- X usage();
- X if (flen == fmax)
- X flist = grow_list(flist, &fmax);
- X ++argv, --argc;
- X flist[flen++] = *argv;
- X
- X *argv = NULL;
- X break;
- X
- X case 'i': /* ignore errors */
- X opts.ignore = 1;
- X break;
- X
- X case 'k': /* give up on current target on error */
- X opts.keepon = 1;
- X break;
- X
- X case 'n': /* don't execute commands */
- X opts.noexec = 1;
- X break;
- X
- X case 'q': /* question mode */
- X opts.query = 1;
- X break;
- X
- X case 'r': /* don't read default.mk */
- X readdef = 0;
- X break;
- X
- X case 's': /* don't echo commands */
- X opts.silent = 1;
- X break;
- X
- X case 'S': /* Undo -k option */
- X no_k = 1;
- X break;
- X
- X case 't': /* touch files, don't build */
- X opts.touch = 1;
- X break;
- X
- X default:
- X usage(); /* never returns */
- X }
- X }
- X
- X if (addflag)
- X {
- X tfree(makeflags);
- X makeflags = tstrcat(tmf, " ");
- X }
- X
- X tfree(tmf);
- X }
- X
- X /* terminate all lists with a NULL pointer */
- X
- X tlist[tlen] = NULL;
- X flist[flen] = NULL;
- X mlist[mlen] = NULL;
- X
- X /* check for -S over-riding -k option */
- X if (no_k)
- X opts.keepon = 0;
- X
- X /* let the caller update the makeflags macro */
- X}
- X
- X
- X/*
- X * grow_list - expand the list of pointers by a factor of two
- X */
- Xchar **
- Xgrow_list(list, len)
- Xchar **list;
- Xint *len;
- X{
- X REGISTER int l;
- X
- X /* if list is NULL, start off with a default list */
- X
- X if (list == NULL)
- X list = (char **) talloc(((l = 1) + 1) * sizeof(char *));
- X else
- X {
- X l = *len; /* get current length */
- X
- X list = (char **) trealloc((char *) list,
- X ((l <<= 1) + 1) * sizeof(char *));
- X }
- X
- X if (list == NULL)
- X terror(1, "too many options");
- X
- X /* if we are initially allocating it, set first pointer to NULL */
- X
- X if (l == 1)
- X *list = NULL;
- X
- X *len = l; /* update current length */
- X return (list);
- X}
- X
- X
- X/*
- X * fopenp - open file in current directory or along PATH
- X */
- XFILE *
- Xfopenp(fname, type)
- Xchar *fname;
- Xchar *type;
- X{
- X REGISTER int len;
- X REGISTER char *fpath;
- X FILE *fd;
- X char *path;
- X char *tp;
- X
- X /* try to open file relative to current directory */
- X if ((fd = fopen(fname, type)) != NULL)
- X return (fd);
- X#ifndef MSDOS
- X /* didn't work, try home directory */
- X if ((path = getenv("HOME")) != NULL)
- X {
- X fpath = talloc(strlen(path) + strlen(fname) + 2);
- X
- X strcpy(fpath, path);
- X len = strlen(fpath) - 1;
- X
- X /* make sure there is a separator between path and filename */
- X
- X if (!strchr(FILE_SEPARATOR, fpath[len]))
- X fpath[++len] = '/';
- X
- X strcpy(&fpath[len + 1], fname); /* attach the filename */
- X fd = fopen(fpath, type);
- X tfree(fpath);
- X
- X if (fd != NULL)
- X return (fd);
- X }
- X#endif
- X /* didn't work, search along path */
- X
- X if ((path = getenv("PATH")) == NULL)
- X return (NULL);
- X
- X path = tstrcpy(path); /* allocate string and copy */
- X fpath = talloc(strlen(path) + strlen(fname) + 2);
- X
- X /* look for tokens separated by semi-colons (;) or colons (:) */
- X
- X tp = token(path, PATH_SEPARATOR, NULL);
- X while (tp != NULL)
- X {
- X strcpy(fpath, tp);
- X len = strlen(fpath) - 1;
- X
- X /* make sure there is a separator between path and filename */
- X
- X if (!strchr(FILE_SEPARATOR, fpath[len]))
- X fpath[++len] = '/';
- X
- X strcpy(&fpath[len + 1], fname); /* attach the filename */
- X if ((fd = fopen(fpath, type)) != NULL)
- X break;
- X
- X tp = token(NULL, PATH_SEPARATOR, NULL);
- X }
- X
- X tfree(path);
- X tfree(fpath);
- X
- X return (fd);
- X}
- X
- X
- X/*
- X * make - guts of the make command
- X * - make all pre-requisites, and if necessary, build target
- X *
- X * returns -1 target was already up to date w.r.t. pre-requisites
- X * 0 target has not been built
- X * 1 target is now built (and up to date)
- X */
- Xmake(targname, worry)
- Xchar *targname;
- Xint worry; /* if set, it is an error to NOT build this */
- X{
- X REGISTER targptr targp;
- X REGISTER fileptr *preqp;
- X REGISTER int mk;
- X fileptr filep;
- X long targtime;
- X long preqtime;
- X
- X mk = 0;
- X
- X /* if recorded time of file is not default, we've already built it */
- X filep = get_file(targname);
- X if (filep && filep->ftime != MAXNEGTIME)
- X return (1);
- X
- X targp = get_target(targname); /* find the target node */
- X if (targp == NULL)
- X return (default_rule(targname, NULL, worry, 0));
- X
- X /* keep actual time of current target */
- X targtime = file_time(targname, 0);
- X
- X /* must build non-existant files, even with no pre-requisites */
- X preqtime = MAXNEGTIME + 1;
- X
- X /* make all pre-requisites */
- X preqp = targp->tpreq;
- X while (preqp && *preqp)
- X {
- X mk |= make((*preqp)->fname, worry);
- X
- X /* keep track of newest pre-requisite */
- X if (preqtime < (*preqp)->ftime)
- X preqtime = (*preqp)->ftime;
- X
- X /* display as necessary */
- X if (opts.depend > 1 ||
- X (opts.depend && (*preqp)->ftime > targtime))
- X {
- X display_prereq(targname, targtime, (*preqp)->fname,
- X (*preqp)->ftime);
- X }
- X
- X ++preqp;
- X }
- X
- X if (targp->tshell == NULL) /* try default rules anyway */
- X {
- X if (default_rule(targname, targp, 0, preqtime > targtime))
- X return (1);
- X return (mk);
- X }
- X else if (preqtime > targtime)
- X {
- X if (opts.touch) /* won't be set when `noexec' */
- X touch_file(targname);
- X else
- X {
- X add_metas("", "", targname);
- X if (build(targp->tshell))
- X return (0);
- X }
- X
- X targp->tfile->ftime = (opts.noexec) ? now
- X : file_time(targname, 1);
- X return (1);
- X }
- X
- X targp->tfile->ftime = targtime;
- X
- X return (mk);
- X}
- X
- X
- X/*
- X * default_rule - try the .SUFFIXES when we don't have an explicit target
- X * - if `worry' is set, it is an ERROR to NOT build this target
- X * - `mustbuild' is set if make() has out-of-date prereq's
- X * but no explicit shell rules
- X */
- Xdefault_rule(targname, targetp, worry, mustbuild)
- Xchar *targname;
- Xtargptr targetp;
- Xint worry;
- Xint mustbuild;
- X{
- X REGISTER targptr targp;
- X REGISTER fileptr *preqp;
- X fileptr filep;
- X char *ext;
- X char *basename;
- X char *preqname;
- X long targtime;
- X long preqtime;
- X int built;
- X char suffrule[80];
- X
- X ext = strrchr(targname, '.'); /* find the extension */
- X if (ext == NULL)
- X ext = targname + strlen(targname);
- X
- X basename = tstrncpy(targname, ext - targname); /* find the base name */
- X
- X targtime = file_time(targname, 0);
- X
- X /* suffix_targ is used to (slightly) speed up this function */
- X preqp = suffix_targ ? suffix_targ->tpreq : NULL;
- X built = 0;
- X
- X while (preqp && *preqp && !built)
- X {
- X /* look for a default rule from SUFFIX to `ext' */
- X strcat(strcpy(suffrule, (*preqp)->fname), ext);
- X targp = get_target(suffrule); /* e.g. `.c.o' */
- X
- X if (targp != NULL)
- X {
- X /* found a rule; see if file exists */
- X preqname = get_preqname(targetp, (*preqp)->fname,
- X basename);
- X preqtime = file_time(preqname, 0);
- X
- X /*
- X * don't bother recursive makes unless necessary e.g.
- X * we have .c.o and .l.c, but also .l.o! we want to
- X * use .l.o if a .c file does not exist
- X */
- X if (preqtime != MAXNEGTIME || mustbuild)
- X built = make(preqname, 0);
- X
- X /* check if pre-req file exists and is newer */
- X preqtime = file_time(preqname, 0);
- X if (preqtime > targtime || (mustbuild && built))
- X {
- X if (opts.depend)
- X {
- X display_prereq(targname, targtime,
- X preqname, preqtime);
- X }
- X
- X if (opts.touch) /* won't be set when `noexec' */
- X touch_file(targname);
- X else
- X {
- X add_metas(basename, preqname, targname);
- X if (build(targp->tshell))
- X return (0);
- X }
- X built = 1;
- X }
- X else if (opts.depend > 1 && preqtime != MAXNEGTIME)
- X {
- X display_prereq(targname, targtime,
- X preqname, preqtime);
- X }
- X
- X tfree(preqname);
- X }
- X
- X ++preqp; /* try next .SUFFIXES rule */
- X }
- X
- X if (!built)
- X {
- X /* didn't find anything; try the default rule */
- X targp = get_target(".DEFAULT");
- X if (targp != NULL)
- X {
- X add_metas(basename, "", targname);
- X if (build(targp->tshell))
- X return (0);
- X built = 1;
- X }
- X else if (targtime == MAXNEGTIME && worry)
- X terror(1, tstrcat("Don't know how to make ", targname));
- X }
- X
- X tfree(basename);
- X
- X /* record the current file time */
- X if ((filep = get_file(targname)) != NULL)
- X {
- X filep->ftime = (built == 1 && opts.noexec) ? now
- X : file_time(targname, 1);
- X }
- X
- X return (built ? built : ((targtime == MAXNEGTIME) ? 0 : 1));
- X}
- X
- X
- X/*
- X * get_preqname - find prerequisite name from target and prerequisite suffix
- X */
- Xchar *
- Xget_preqname(targp, suffix, basename)
- Xtargptr targp;
- Xchar *suffix;
- Xchar *basename;
- X{
- X fileptr *preqp;
- X char *preqf;
- X char *basef;
- X int i;
- X
- X if (targp != NULL)
- X {
- X /* strip the directory name from the basename */
- X basef = tsplit(basename, FILE_SEPARATOR, NULL);
- X
- X /* look through prerequisite list for file with right name */
- X for (preqp = targp->tpreq; preqp && *preqp; ++preqp)
- X {
- X /* split the pre-requisite into dir and filenames */
- X preqf = tsplit((*preqp)->fname, FILE_SEPARATOR, NULL);
- X
- X /* see if the filename part matches the target */
- X for (i = 0; preqf[i] != '\0'; i++)
- X {
- X if (preqf[i] != basef[i])
- X break;
- X }
- X
- X /* if we differed only on the suffix, we're okay */
- X if (strcmp(preqf + i, suffix) == 0)
- X return (tstrcpy((*preqp)->fname));
- X }
- X#ifdef ALL_PREQS
- X /* didn't find a matching basename + suffix in the preq-list. */
- X /* look through prerequisite list for file with right suffix. */
- X for (preqp = targp->tpreq; preqp && *preqp; ++preqp)
- X {
- X preqf = strrchr((*preqp)->fname, '.');
- X if (preqf == NULL)
- X continue;
- X
- X /* take the first file which has right suffix */
- X if (strcmp(suffix, preqf) == 0)
- X return (tstrcpy((*preqp)->fname));
- X }
- X#endif /* ALL_PREQS */
- X }
- X
- X /* didn't find one, so try forming one using basename + suffix */
- X
- X return (tstrcat(basename, suffix));
- X}
- X
- X
- X/*
- X * add_metas - add symbols for $*, $< and $@
- X */
- Xadd_metas(basename, preqname, targname)
- Xchar *basename;
- Xchar *preqname;
- Xchar *targname;
- X{
- X /* $* is the basename */
- X add_symbol("*", basename, 0);
- X split_meta("*", basename);
- X
- X add_symbol("<", preqname, 0);
- X split_meta("<", preqname);
- X
- X add_symbol("@", targname, 0);
- X split_meta("@", targname);
- X}
- X
- X
- X/*
- X * split_meta - split a metasymbol into Directory and File parts
- X */
- Xsplit_meta(sym, name)
- Xchar *sym;
- Xchar *name;
- X{
- X char *dname;
- X char *dsym;
- X char *fsym;
- X
- X /* construct the macro names (e.g. $(*D), $(@F)) */
- X dsym = tstrcat(sym, "D");
- X fsym = tstrcat(sym, "F");
- X
- X add_symbol(fsym, tsplit(name, FILE_SEPARATOR, &dname), 0);
- X
- X if (dname == NULL)
- X add_symbol(dsym, ".", 0);
- X else
- X {
- X add_symbol(dsym, dname, 0);
- X tfree(dname);
- X }
- X
- X tfree(dsym);
- X tfree(fsym);
- X}
- X
- X
- X/*
- X * touch_file - set the MODIFICATION time of the file to NOW
- X */
- Xtouch_file(targname)
- Xchar *targname;
- X{
- X REGISTER int handle;
- X
- X#ifndef MSDOS
- X time_t timep[2];
- X
- X time(&timep[0]);
- X timep[1] = timep[0];
- X handle = utime(targname, timep);
- X#else
- X handle = utime(targname, NULL);
- X#endif
- X fputs("touch ", stdout);
- X puts(targname);
- X
- X if (handle == 0)
- X return;
- X
- X /* create the file, if it did not exist */
- X if (errno == ENOENT)
- X {
- X handle = open(targname, O_CREAT | O_TRUNC, S_IWRITE);
- X if (handle != -1)
- X {
- X close(handle);
- X return;
- X }
- X }
- X
- X perror("touch");
- X exit(1);
- X}
- X
- Xdisplay_prereq(targname, targtime, preqname, preqtime)
- Xchar *targname;
- Xlong targtime;
- Xchar *preqname;
- Xlong preqtime;
- X{
- X#ifdef MSDOS
- X char chtime[10];
- X
- X fputs(targname, stdout);
- X fputs(" (", stdout);
- X fputs(ltoa(targtime, chtime, 16), stdout);
- X fputs((targtime <= preqtime) ? ") older than " : ") newer than ", stdout);
- X fputs(preqname, stdout);
- X fputs(" (", stdout);
- X fputs(ltoa(preqtime, chtime, 16), stdout);
- X puts(")");
- X#else
- X printf("%s (%08lx) %s than %s (%08lx)\n",
- X targname, targtime,
- X (targtime < preqtime) ? "older" : "newer",
- X preqname, preqtime);
- X#endif
- X}
- X
- X
- Xlong
- Xfile_time(fname, built)
- Xchar *fname;
- Xint built;
- X{
- X struct stat sbuf;
- X
- X /*
- X * if the file is supposedly built, but still does not exists, just
- X * fake it by returning the current time.
- X */
- X if (stat(fname, &sbuf) != 0)
- X return (built ? now : MAXNEGTIME);
- X return (sbuf.st_mtime);
- X}
- X
- X
- Xusage()
- X{
- X puts("make [-f filename] [-dDiknqrsSt] [target ...] [macro=value ...]");
- X exit(1);
- X}
- END_OF_FILE
- if test 17680 -ne `wc -c <'make.c'`; then
- echo shar: \"'make.c'\" unpacked with wrong size!
- fi
- # end of 'make.c'
- fi
- if test -f 'tstring.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tstring.c'\"
- else
- echo shar: Extracting \"'tstring.c'\" \(5471 characters\)
- sed "s/^X//" >'tstring.c' <<'END_OF_FILE'
- X/*
- X * tstring.c
- X *
- X * 88-10-01 v1.0 created by greg yachuk, placed in the public domain
- X * 88-10-06 v1.1 changed prerequisite list handling
- X * 88-11-11 v1.2 fixed some bugs and added environment variables
- X * 89-07-12 v1.3 stop appending shell commands, and flush output
- X * 89-08-01 v1.4 AB lots of new options and code
- X * 89-10-30 v1.5 greggy -f -S -q options, took some changes from v1.4
- X *
- X */
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <malloc.h>
- X#include <string.h>
- X
- X#include "tstring.h"
- X
- X
- Xchar *
- Xtalloc(n)
- Xint n;
- X{
- X register char *s;
- X
- X s = malloc(n);
- X if (s == NULL)
- X terror(1, "no free memory");
- X return (s);
- X}
- X
- X
- Xchar *
- Xtrealloc(s, n)
- Xregister char *s;
- Xint n;
- X{
- X s = realloc(s, n);
- X if (s == NULL)
- X talloc(n); /* force an error */
- X return (s);
- X}
- X
- X
- Xchar *
- Xtstrncpy(s, n)
- Xregister char *s;
- Xint n;
- X{
- X s = strncpy(talloc(n + 1), s, n);
- X s[n] = '\0';
- X return (s);
- X}
- X
- X
- Xterror(n, s)
- Xint n;
- Xchar *s;
- X{
- X fputs("Make: ", stderr);
- X fputs(s, stderr);
- X putc('\n', stderr);
- X if (n)
- X exit(n);
- X}
- X
- X
- X/*
- X * tstrspan - move to the end of a quoted string, ignoring escaped quotes
- X */
- Xchar *
- Xtstrspan(str)
- Xchar *str;
- X{
- X char quote;
- X
- X if (*str != '\'' && *str != '"')
- X return (str + 1);
- X
- X quote = *str++;
- X
- X while (*str && *str != quote)
- X {
- X /* check for escaped quote */
- X if (*str == '\\' && str[1] == quote)
- X ++str;
- X ++str;
- X }
- X
- X return (str);
- X}
- X
- X
- X/*
- X * tunquote - remove quotes from a string
- X */
- Xchar *
- Xtunquote(str)
- Xchar *str;
- X{
- X char *s;
- X char *d;
- X
- X d = s = str;
- X
- X while (*s)
- X {
- X while (*s && *s == '"')
- X ++s;
- X
- X while (*s && *s != '"')
- X *d++ = *s++;
- X }
- X
- X *d = '\0';
- X
- X return (str);
- X}
- X
- X
- X/*
- X * tsplit - split a string into two components, normally a directory
- X * path and a filename. If a pointer to a directory is
- X * supplied, a string is allocated to contain the directory.
- X * The filename is returned as a pointer into the supplied
- X * string.
- X */
- Xchar *
- Xtsplit(s, seps, dp)
- Xchar *s;
- Xchar *seps;
- Xchar **dp;
- X{
- X char *d; /* directory portion */
- X char *f; /* file portion */
- X
- X d = s;
- X
- X /* find the final separator */
- X while ((f = strpbrk(d, seps)) != NULL)
- X d = f + 1;
- X
- X /* back up to final component */
- X f = d;
- X
- X /* if we are still at the beginning, there was no Directory */
- X if (d == s || dp == NULL)
- X d = NULL;
- X else
- X {
- X int len;
- X
- X /*
- X * by the time we get here, d points to the final separator
- X * char. we can substitute a NULL for this sep-char. Thus,
- X * we don't need to add 1 in the following length
- X * calculation.
- X */
- X len = d - s;
- X
- X d = talloc(len);
- X d[--len] = '\0';
- X while (--len >= 0)
- X d[len] = s[len];
- X }
- X
- X if (dp != NULL)
- X *dp = d;
- X
- X return (f);
- X}
- X
- X
- X/*
- X * token - take an input string and return a token each call
- X * - default token delimiter characters are `isspace()'
- X * - separator chars are in addition to `isspace()'
- X * - text between quotes (" and ') is a single token
- X * - if requested, the separator char is returned
- X *
- X * called as s = token(string, seps, &schar);
- X * or s = token(string, NULL, NULL);
- X *
- X * followed by s = token(NULL, seps, NULL);
- X * or s = token(NULL, NULL, &schar);
- X *
- X * returns NULL when no more tokens are available
- X */
- Xchar *
- Xtoken(s, sep, schar)
- Xchar *s;
- Xchar *sep;
- Xchar *schar;
- X{
- X static char *olds = NULL;
- X
- X if (s)
- X olds = s; /* we are starting all over again */
- X
- X if (schar)
- X *schar = '\0';
- X
- X if (!olds || !*olds)
- X return (NULL); /* no tokens left */
- X
- X while (isspace(*olds) || (sep && strchr(sep, *olds)))
- X ++olds; /* skip leading spaces and sep's */
- X
- X if (*olds == NULL)
- X return (NULL); /* remainder is all separator's */
- X
- X s = olds;
- X
- X while (*olds)
- X {
- X if (isspace(*olds) || (sep && strchr(sep, *olds)))
- X {
- X if (schar)
- X *schar = *olds;
- X *olds++ = '\0'; /* delimit the token */
- X return (s);
- X }
- X else if (*olds == '"' || *olds == '\'')
- X {
- X olds = tstrspan(olds);
- X if (*olds != '\0')
- X ++olds; /* didn't hit eos, so skip quote */
- X }
- X else
- X ++olds; /* otherwise, pass over char */
- X }
- X
- X olds = NULL;
- X return (s); /* return last token */
- X}
- X
- X
- X/*
- X * tokenize - chop a string up into an array of (char *)'s
- X */
- Xchar **
- Xtokenize(input)
- Xchar *input;
- X{
- X char **argv;
- X register int argc = 0;
- X register int alen;
- X
- X alen = 20; /* good initial guess */
- X argv = (char **) talloc((alen + 1) * sizeof(char *));
- X
- X input = token(input, NULL, NULL); /* use default separators */
- X while (input)
- X {
- X if (alen == argc)
- X argv = (char **) trealloc((char *) argv,
- X (alen <<= 1) * sizeof(char *));
- X argv[argc++] = input;
- X input = token(NULL, NULL, NULL);
- X }
- X
- X argv[argc] = NULL; /* mark end of array */
- X
- X return (argv);
- X}
- X
- X
- X/*
- X * tgets - read input, swallowing escaped newlines as necessary
- X */
- Xchar *
- Xtgets(fd)
- XFILE *fd;
- X{
- X static char *input = NULL;
- X static int inlen = 0;
- X register char *ep;
- X int len;
- X
- X if (inlen == 0)
- X input = talloc(inlen = 162);
- X
- X input[inlen - 2] = '\n';
- X ep = input - 1;
- X while ((fgets(input, inlen, fd)) != NULL)
- X {
- X for (;;)
- X {
- X while (input[inlen - 2] != '\n' && input[inlen - 2] != '\0')
- X {
- X len = inlen;
- X input = trealloc(input, inlen <<= 1);
- X ep = &input[len - 2];
- X input[inlen - 2] = '\n';
- X fgets(ep + 1, len + 1, fd);
- X }
- X
- X while (*++ep);
- X *--ep = '\0';
- X do
- X {
- X --ep;
- X } while (ep >= input && isspace(*ep));
- X
- X if (ep > input && *ep == '\\' && *--ep != '\\')
- X fgets(ep + 1, inlen - (ep - input) - 1, fd);
- X else
- X break;
- X }
- X
- X return (input);
- X }
- X
- X inlen = 0;
- X tfree(input);
- X input = NULL;
- X
- X return (NULL);
- X}
- END_OF_FILE
- if test 5471 -ne `wc -c <'tstring.c'`; then
- echo shar: \"'tstring.c'\" unpacked with wrong size!
- fi
- # end of 'tstring.c'
- fi
- echo shar: End of archive 1 \(of 3\).
- cp /dev/null ark1isdone
- MISSING=""
- for I in 1 2 3 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 3 archives.
- rm -f ark[1-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-
-